using System;
using System.Collections.Generic;

namespace LaplaceMeshDeformer
{
    /// <summary>
    /// 三角网格类
    /// 实现半边数据结构来表示三角网格
    /// </summary>
    public class TriMesh
    {
        #region 内部类定义

        /// <summary>
        /// 顶点类
        /// </summary>
        public class Vertex
        {
            private Vector3D position;         // 顶点位置
            private Vector3D normal;           // 顶点法线
            private Halfedge halfedge;         // 从该顶点出发的半边
            private int index;                 // 顶点索引
            private bool selected;             // 是否被选中

            /// <summary>
            /// 获取或设置顶点位置
            /// </summary>
            public Vector3D Position
            {
                get { return position; }
                set { position = value; }
            }

            /// <summary>
            /// 获取或设置顶点法线
            /// </summary>
            public Vector3D Normal
            {
                get { return normal; }
                set { normal = value; }
            }

            /// <summary>
            /// 获取或设置该顶点的一条半边
            /// </summary>
            public Halfedge Halfedge
            {
                get { return halfedge; }
                set { halfedge = value; }
            }

            /// <summary>
            /// 获取顶点索引
            /// </summary>
            public int Index
            {
                get { return index; }
                set { index = value; }
            }

            /// <summary>
            /// 获取或设置顶点是否被选中
            /// </summary>
            public bool Selected
            {
                get { return selected; }
                set { selected = value; }
            }

            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="position">顶点位置</param>
            /// <param name="index">顶点索引</param>
            public Vertex(Vector3D position, int index)
            {
                this.position = position;
                this.normal = new Vector3D();
                this.halfedge = null;
                this.index = index;
                this.selected = false;
            }

            /// <summary>
            /// 获取从该顶点出发的所有半边
            /// </summary>
            /// <returns>半边列表</returns>
            public List<Halfedge> GetOutgoingHalfedges()
            {
                List<Halfedge> outgoing = new List<Halfedge>();

                if (halfedge == null)
                {
                    return outgoing;
                }

                Halfedge start = halfedge;
                Halfedge current = start;

                do
                {
                    outgoing.Add(current);

                    if (current.Twin == null)
                        break;

                    current = current.Twin.Next;

                    if (current == null)
                        break;

                } while (current != start);

                return outgoing;
            }
        }

        /// <summary>
        /// 面类
        /// </summary>
        public class Face
        {
            private Halfedge halfedge;     // 面的一条半边
            private Vector3D normal;       // 面法线
            private int index;             // 面索引
            private List<int> vertexIndices; // 面的顶点索引

            /// <summary>
            /// 获取或设置面的一条半边
            /// </summary>
            public Halfedge Halfedge
            {
                get { return halfedge; }
                set { halfedge = value; }
            }

            /// <summary>
            /// 获取或设置面法线
            /// </summary>
            public Vector3D Normal
            {
                get { return normal; }
                set { normal = value; }
            }

            /// <summary>
            /// 获取面索引
            /// </summary>
            public int Index
            {
                get { return index; }
                set { index = value; }
            }

            /// <summary>
            /// 获取面的顶点索引列表
            /// </summary>
            public List<int> VertexIndices
            {
                get { return vertexIndices; }
                set { vertexIndices = value; }
            }

            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="index">面索引</param>
            public Face(int index)
            {
                this.halfedge = null;
                this.normal = new Vector3D();
                this.index = index;
                this.vertexIndices = new List<int>();
            }

            /// <summary>
            /// 获取面的顶点数量
            /// </summary>
            /// <returns>顶点数量</returns>
            public int VertexCount
            {
                get { return vertexIndices.Count; }
            }

            /// <summary>
            /// 获取指定索引处的顶点索引
            /// </summary>
            /// <param name="i">索引</param>
            /// <returns>顶点索引</returns>
            public int GetVertexIndex(int i)
            {
                if (i < 0 || i >= vertexIndices.Count)
                {
                    throw new IndexOutOfRangeException("顶点索引超出范围");
                }
                return vertexIndices[i];
            }
        }

        /// <summary>
        /// 半边类
        /// </summary>
        public class Halfedge
        {
            private Vertex target;         // 半边指向的顶点
            private Face face;             // 半边所属的面
            private Halfedge next;         // 下一条半边
            private Halfedge twin;         // 孪生半边
            private int index;             // 半边索引

            /// <summary>
            /// 获取或设置半边指向的顶点
            /// </summary>
            public Vertex Target
            {
                get { return target; }
                set { target = value; }
            }

            /// <summary>
            /// 获取或设置半边所属的面
            /// </summary>
            public Face Face
            {
                get { return face; }
                set { face = value; }
            }

            /// <summary>
            /// 获取或设置下一条半边
            /// </summary>
            public Halfedge Next
            {
                get { return next; }
                set { next = value; }
            }

            /// <summary>
            /// 获取或设置孪生半边
            /// </summary>
            public Halfedge Twin
            {
                get { return twin; }
                set { twin = value; }
            }

            /// <summary>
            /// 获取或设置半边索引
            /// </summary>
            public int Index
            {
                get { return index; }
                set { index = value; }
            }

            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="index">半边索引</param>
            public Halfedge(int index)
            {
                this.target = null;
                this.face = null;
                this.next = null;
                this.twin = null;
                this.index = index;
            }
        }

        /// <summary>
        /// 边类
        /// </summary>
        public class Edge
        {
            private Halfedge halfedge;     // 边的一条半边
            private int index;             // 边索引

            /// <summary>
            /// 获取或设置边的一条半边
            /// </summary>
            public Halfedge Halfedge
            {
                get { return halfedge; }
                set { halfedge = value; }
            }

            /// <summary>
            /// 获取或设置边索引
            /// </summary>
            public int Index
            {
                get { return index; }
                set { index = value; }
            }

            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="halfedge">边的一条半边</param>
            /// <param name="index">边索引</param>
            public Edge(Halfedge halfedge, int index)
            {
                this.halfedge = halfedge;
                this.index = index;
            }
        }

        #endregion

        #region 成员变量和属性

        private List<Vertex> vertices;     // 顶点列表
        private List<Face> faces;          // 面列表
        private List<Halfedge> halfedges;  // 半边列表
        private List<Edge> edges;          // 边列表
        private bool connected;            // 是否建立了连接关系

        /// <summary>
        /// 获取顶点数量
        /// </summary>
        public int VertexCount => vertices.Count;

        /// <summary>
        /// 获取面数量
        /// </summary>
        public int FaceCount => faces.Count;

        /// <summary>
        /// 获取半边数量
        /// </summary>
        public int HalfedgeCount => halfedges.Count;

        /// <summary>
        /// 获取边数量
        /// </summary>
        public int EdgeCount => edges.Count;

        /// <summary>
        /// 获取是否已建立连接关系
        /// </summary>
        public bool IsConnected => connected;

        #endregion

        #region 构造函数

        /// <summary>
        /// 默认构造函数
        /// </summary>
        public TriMesh()
        {
            vertices = new List<Vertex>();
            faces = new List<Face>();
            halfedges = new List<Halfedge>();
            edges = new List<Edge>();
            connected = false;
        }

        #endregion

        #region 网格操作方法

        /// <summary>
        /// 添加顶点
        /// </summary>
        /// <param name="position">顶点位置</param>
        /// <returns>顶点索引</returns>
        public int AddVertex(Vector3D position)
        {
            int index = vertices.Count;
            vertices.Add(new Vertex(position, index));
            return index;
        }

        /// <summary>
        /// 添加面
        /// </summary>
        /// <param name="vertexIndices">面的顶点索引</param>
        /// <returns>面索引</returns>
        public int AddFace(List<int> vertexIndices)
        {
            // 检查顶点索引是否有效
            foreach (int index in vertexIndices)
            {
                if (index < 0 || index >= vertices.Count)
                {
                    throw new ArgumentException("无效的顶点索引");
                }
            }

            // 创建新面
            int faceIndex = faces.Count;
            Face face = new Face(faceIndex);
            face.VertexIndices.AddRange(vertexIndices);
            faces.Add(face);

            // 重置连接状态
            connected = false;
            
            return faceIndex;
        }

        /// <summary>
        /// 获取顶点
        /// </summary>
        /// <param name="index">顶点索引</param>
        /// <returns>顶点对象</returns>
        public Vertex GetVertex(int index)
        {
            if (index < 0 || index >= vertices.Count)
            {
                throw new IndexOutOfRangeException("顶点索引超出范围");
            }
            return vertices[index];
        }

        /// <summary>
        /// 获取面
        /// </summary>
        /// <param name="index">面索引</param>
        /// <returns>面对象</returns>
        public Face GetFace(int index)
        {
            if (index < 0 || index >= faces.Count)
            {
                throw new IndexOutOfRangeException("面索引超出范围");
            }
            return faces[index];
        }

        /// <summary>
        /// 获取半边
        /// </summary>
        /// <param name="index">半边索引</param>
        /// <returns>半边对象</returns>
        public Halfedge GetHalfedge(int index)
        {
            if (index < 0 || index >= halfedges.Count)
            {
                throw new IndexOutOfRangeException("半边索引超出范围");
            }
            return halfedges[index];
        }

        /// <summary>
        /// 获取边
        /// </summary>
        /// <param name="index">边索引</param>
        /// <returns>边对象</returns>
        public Edge GetEdge(int index)
        {
            if (index < 0 || index >= edges.Count)
            {
                throw new IndexOutOfRangeException("边索引超出范围");
            }
            return edges[index];
        }

        /// <summary>
        /// 清空网格
        /// </summary>
        public void Clear()
        {
            vertices.Clear();
            faces.Clear();
            halfedges.Clear();
            edges.Clear();
            connected = false;
        }

        /// <summary>
        /// 建立网格连接关系
        /// </summary>
        public void BuildConnectivity()
        {
            if (connected)
            {
                return;
            }

            // 清空现有的半边和边
            halfedges.Clear();
            edges.Clear();

            // 重置所有顶点和面的连接信息
            foreach (Vertex v in vertices)
            {
                v.Halfedge = null;
            }

            foreach (Face f in faces)
            {
                f.Halfedge = null;
            }

            // 用于查找半边的字典，键为(source, target)顶点索引对
            Dictionary<(int, int), Halfedge> edgeMap = new Dictionary<(int, int), Halfedge>();

            // 为每个面创建半边
            int halfedgeIndex = 0;
            foreach (Face face in faces)
            {
                int faceVertexCount = face.VertexCount;
                List<Halfedge> faceHalfedges = new List<Halfedge>();

                // 创建面的半边
                for (int i = 0; i < faceVertexCount; i++)
                {
                    Halfedge he = new Halfedge(halfedgeIndex++);
                    halfedges.Add(he);
                    faceHalfedges.Add(he);

                    // 设置半边指向的顶点
                    int targetIndex = face.GetVertexIndex(i);
                    he.Target = vertices[targetIndex];

                    // 设置半边所属的面
                    he.Face = face;
                }

                // 连接面内的半边
                for (int i = 0; i < faceVertexCount; i++)
                {
                    Halfedge current = faceHalfedges[i];
                    Halfedge next = faceHalfedges[(i + 1) % faceVertexCount];
                    current.Next = next;
                }

                // 设置面的半边指针
                face.Halfedge = faceHalfedges[0];

                // 添加到边映射表
                for (int i = 0; i < faceVertexCount; i++)
                {
                    int sourceIndex = face.GetVertexIndex(i);
                    int targetIndex = face.GetVertexIndex((i + 1) % faceVertexCount);
                    edgeMap[(sourceIndex, targetIndex)] = faceHalfedges[i];
                }
            }

            // 查找并连接孪生半边
            int edgeIndex = 0;
            foreach (var kvp in edgeMap)
            {
                var (sourceIndex, targetIndex) = kvp.Key;
                Halfedge he = kvp.Value;

                // 查看是否存在反向的半边
                if (edgeMap.TryGetValue((targetIndex, sourceIndex), out Halfedge twin))
                {
                    // 如果尚未设置孪生关系，则设置
                    if (he.Twin == null && twin.Twin == null)
                    {
                        he.Twin = twin;
                        twin.Twin = he;
                    }
                }

                // 如果这条半边还没有被处理过，创建一条新的边
                if (he.Twin == null || he.Index < he.Twin.Index)
                {
                    Edge edge = new Edge(he, edgeIndex++);
                    edges.Add(edge);
                }
            }

            // 设置顶点的半边指针
            for (int i = 0; i < vertices.Count; i++)
            {
                Vertex v = vertices[i];
                foreach (Halfedge he in halfedges)
                {
                    if (he.Target == v)
                    {
                        v.Halfedge = he;
                        break;
                    }
                }
            }

            connected = true;
        }

        /// <summary>
        /// 选择所有顶点
        /// </summary>
        public void SelectAllVertices()
        {
            foreach (Vertex v in vertices)
            {
                v.Selected = true;
            }
        }

        /// <summary>
        /// 取消选择所有顶点
        /// </summary>
        public void UnselectAllVertices()
        {
            foreach (Vertex v in vertices)
            {
                v.Selected = false;
            }
        }

        /// <summary>
        /// 获取当前选中的顶点索引列表
        /// </summary>
        /// <returns>选中的顶点索引列表</returns>
        public List<int> GetSelectedVertices()
        {
            List<int> selected = new List<int>();
            for (int i = 0; i < vertices.Count; i++)
            {
                if (vertices[i].Selected)
                {
                    selected.Add(i);
                }
            }
            return selected;
        }

        /// <summary>
        /// 设置选中的顶点
        /// </summary>
        /// <param name="indices">要选中的顶点索引列表</param>
        public void SetSelectedVertices(List<int> indices)
        {
            UnselectAllVertices();
            foreach (int index in indices)
            {
                if (index >= 0 && index < vertices.Count)
                {
                    vertices[index].Selected = true;
                }
            }
        }

        #endregion
    }
}